﻿using Jeneva;
using Jeneva.Aspnetmvc;
using Jeneva.Impl;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace JenevaParserSpeedTest
{
    class Program
    {
        static JsonSerializerSettings settings = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, ContractResolver = new LowerCasePropertyContractResolver() };
        static IJsonParser parser = new JsonParser(JenevaContext.Current);

        static void Main(string[] args)
        {
            Console.WriteLine("This test shows performance difference in deserialization");
            Console.WriteLine("Json.Net (Newtonsoft) vs Jeneva.Net");
            Console.WriteLine("100 objects with different field types and subclasses");
            Console.WriteLine();
            List<string> jsonList = GenerateJsons();

            Stopwatch stopwatch = Stopwatch.StartNew();
            foreach (string json in jsonList)
            {
                ParseByJsonNet(json);
            }

            stopwatch.Stop();
            Console.WriteLine("Json.Net (Newtonsoft) - elapsed time is:\t" + stopwatch.Elapsed);


            stopwatch = Stopwatch.StartNew();
            foreach (string json in jsonList)
            {
                ParseByJeneva(json);
            }

            stopwatch.Stop();
            Console.WriteLine("Jeneva.Net (Upida.Net) - elapsed time is:\t" + stopwatch.Elapsed);
            Console.WriteLine();
        }

        internal class LowerCasePropertyContractResolver : DefaultContractResolver
        {
            protected override string ResolvePropertyName(string propertyName)
            {
                return string.Concat(Char.ToLower(propertyName[0]), propertyName.Substring(1));
            }
        }

        private static List<string> GenerateJsons()
        {
            JsonClass oneObject = JsonClass.Generate();
            List<string> jsonList = new List<string>();
            int index = 0;
            while (index < 100)
            {
                jsonList.Add(
                    JsonConvert.SerializeObject(oneObject, settings));
                index++;
            }

            return jsonList;
        }

        private static void ParseByJeneva(string json)
        {
            JToken jsonToken = (JToken)JsonConvert.DeserializeObject(json, typeof(JToken));
            JsonClass parsedData = (JsonClass)parser.Parse(jsonToken, typeof(JsonClass));
        }

        private static void ParseByJsonNet(string json)
        {
            JsonClass parsedData = (JsonClass)JsonConvert.DeserializeObject(json, typeof(JsonClass));
        }
    }

    public class JsonClass : Dtobase
    {
        [Dto(1)]
        public int? Int1 { get; set; }

        [Dto(2)]
        public int? Int2 { get; set; }

        [Dto(3)]
        public int? Int3 { get; set; }

        [Dto(1)]
        public string String1 { get; set; }

        [Dto(2)]
        public string String2 { get; set; }

        [Dto(3)]
        public string String3 { get; set; }

        [Dto(4)]
        public string String4 { get; set; }

        [Dto(5)]
        public string String5 { get; set; }

        [Dto(6)]
        public string String6 { get; set; }

        [Dto(1)]
        public DateTime? DateTime1 { get; set; }

        [Dto(2)]
        public DateTime? DateTime2 { get; set; }

        [Dto(1)]
        public short? Short1 { get; set; }

        [Dto(2)]
        public short? Short2 { get; set; }

        [Dto(1)]
        public long? Long1 { get; set; }

        [Dto(2)]
        public long? Long2 { get; set; }

        [Dto(1)]
        public decimal? Decimal1 { get; set; }

        [Dto(2)]
        public decimal? Decimal2 { get; set; }

        [Dto(1)]
        public double? Double1 { get; set; }

        [Dto(2)]
        public double? Double2 { get; set; }

        [Dto(1)]
        public IList<JsonClass> List1 { get; set; }

        public static JsonClass Generate()
        {
            JsonClass child1 = new JsonClass()
            {
                Int1 = 100,
                Int2 = 200,
                Int3 = 5000,
                String1 = "A",
                String2 = "AAAAA",
                String3 = "AAAAAAAA AAAAAA AAAAAAAA",
                String4 = "$$$$",
                String5 = "AAAA $$$$ FFFFF ^^^^^^ hhhhhhhh ASASASSAS JJDJDJDJDJ SASASSA",
                String6 = null,
                DateTime1 = new DateTime(2000, 10, 10, 10, 10, 10),
                DateTime2 = new DateTime(2000, 10, 10, 10, 10, 10),
                Short1 = 400,
                Short2 = 500,
                Long1 = 99999999999999,
                Long2 = 11111111111111,
                Decimal1 = 11111.22222m,
                Decimal2 = 44444.55555m,
                Double1 = 11111.22222,
                Double2 = 44444.55555
            };
            JsonClass child2 = new JsonClass()
            {
                Int1 = 100,
                Int2 = 200,
                Int3 = 5000,
                String1 = "A",
                String2 = "AAAAA",
                String3 = "AAAAAAAA AAAAAA AAAAAAAA",
                String4 = "$$$$",
                String5 = "AAAA $$$$ FFFFF ^^^^^^ hhhhhhhh ASASASSAS JJDJDJDJDJ SASASSA",
                String6 = null,
                DateTime1 = new DateTime(2000, 10, 10, 10, 10, 10),
                DateTime2 = new DateTime(2000, 10, 10, 10, 10, 10),
                Short1 = 400,
                Short2 = 500,
                Long1 = 99999999999999,
                Long2 = 11111111111111,
                Decimal1 = 11111.22222m,
                Decimal2 = 44444.55555m,
                Double1 = 11111.22222,
                Double2 = 44444.55555
            };
            JsonClass parent = new JsonClass()
            {
                Int1 = 100,
                Int2 = 200,
                Int3 = 5000,
                String1 = "A",
                String2 = "AAAAA",
                String3 = "AAAAAAAA AAAAAA AAAAAAAA",
                String4 = "$$$$",
                String5 = "AAAA $$$$ FFFFF ^^^^^^ hhhhhhhh ASASASSAS JJDJDJDJDJ SASASSA",
                String6 = null,
                DateTime1 = new DateTime(2000, 10, 10, 10, 10, 10),
                DateTime2 = new DateTime(2000, 10, 10, 10, 10, 10),
                Short1 = 400,
                Short2 = 500,
                Long1 = 99999999999999,
                Long2 = 11111111111111,
                Decimal1 = 11111.22222m,
                Decimal2 = 44444.55555m,
                Double1 = 11111.22222,
                Double2 = 44444.55555,
                List1 = new List<JsonClass> { child1, child2 }
            };
            return parent;
        }
    }
}